home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / nan_news / toolkit / fttext.c < prev    next >
C/C++ Source or Header  |  1991-08-17  |  17KB  |  660 lines

  1. /*
  2.  * File......: TEXT.C
  3.  * Author....: Brice de Ganahl
  4.  * Date......: $Date:   17 Aug 1991 15:31:08  $
  5.  * Revision..: $Revision:   1.4  $
  6.  * Log file..: $Logfile:   E:/nanfor/src/fttext.c_v  $
  7.  * 
  8.  * This is an original work by Brice de Ganahl and is placed in the
  9.  * public domain.   I hope it is useful but have no intention to
  10.  * support it and do not claim that it is fit for any particular use.
  11.  *
  12.  * Doc headers by Glenn Scott & Don Caton
  13.  *
  14.  *
  15.  * Modification history:
  16.  * ---------------------
  17.  *
  18.  * $Log:   E:/nanfor/src/fttext.c_v  $
  19.  * 
  20.  *    Rev 1.4   17 Aug 1991 15:31:08   GLENN
  21.  * Don Caton fixed some spelling errors in the doc
  22.  * 
  23.  *    Rev 1.3   15 Aug 1991 23:08:36   GLENN
  24.  * Forest Belt proofread/edited/cleaned up doc
  25.  * 
  26.  *    Rev 1.2   29 Apr 1991 08:02:12   GLENN
  27.  * Minor adjustments to documentation block
  28.  * 
  29.  *    Rev 1.1   29 Apr 1991 08:00:26   GLENN
  30.  * ft_flastrec() -- name was longer than 10 characters so linkers couldn't
  31.  * find the symbol.  Just hacked off the last "c" so it is really 
  32.  * ft_flastre().  Sorry, folks.  -- Glenn
  33.  * 
  34.  *    Rev 1.0   01 Apr 1991 01:02:48   GLENN
  35.  * Nanforum Toolkit
  36.  * 
  37.  */
  38.  
  39. /*  Notes:
  40.  
  41.      The Clipper internal functions used seem to be stable across
  42.      versions but nothing is guaranteed.  These functions begin
  43.      with _t, are used for file I/O, and are compatible with their
  44.      ANSI counterparts (just strip the _t and you have the ANSI name).
  45.      See text.h for the prototypes.
  46.  
  47.      I compile these functions with the following MicroSoft C parameters:
  48.  
  49.           cl  /c /AL /Od /Zl /Zi /FPa /Gs /W3 text.c
  50.  
  51.      Note that the /Od defeats optimization and is necessary only for
  52.      compatibility with Blinker, Warplink, etc.  If you are not overlaying
  53.      this code you may want to change this to /Oalt.  Likewise, the
  54.      /Zi is for symbolic debugging info which you will want to omit in
  55.      any final compiles.
  56.  
  57.      Some sample Clipper code which would use these functions is listed
  58.      below.  It will print out the contents of this file.
  59.  
  60.               ft_fuse( "text.c" )
  61.               do while !ft_feof()
  62.                  ? ft_freadln()
  63.                  ft_fskip()
  64.               enddo
  65.               ft_fuse()
  66.  
  67.  
  68. */
  69.  
  70.  
  71. #include "extend.h"
  72. #include "fttext.h"
  73.  
  74. #define TEXT_WORKAREAS 10
  75.  
  76. static long recno[TEXT_WORKAREAS];
  77. static long offset[TEXT_WORKAREAS];
  78. static int  handles[TEXT_WORKAREAS];
  79. static char *b;
  80. static char *c;
  81. static int  area = 0;
  82. static long last_rec[TEXT_WORKAREAS];
  83. static long last_off[TEXT_WORKAREAS];
  84. static long lastbyte[TEXT_WORKAREAS];
  85. static int  isEof[TEXT_WORKAREAS];
  86.  
  87.  
  88. /*  $DOC$
  89.  *  $FUNCNAME$
  90.  *     FT_FUSE()
  91.  *  $CATEGORY$
  92.  *     File I/O
  93.  *  $ONELINER$
  94.  *     Open or close a text file for use by the FT_F* functions
  95.  *  $SYNTAX$
  96.  *     FT_FUSE( [ <cFile> ] ) -> nHandle | NIL
  97.  *  $ARGUMENTS$
  98.  *     <cFile> is the text file you want to open.  If not specified,
  99.  *     the file currently open, if any, will be closed.
  100.  *  $RETURNS$
  101.  *     If <cFile> is passed and the file is opened successfully, an
  102.  *     integer containing the file handle.  If the file cannot be
  103.  *     opened, -1 will be returned.
  104.  *
  105.  *     If FT_FUSE() is called without any arguments, it will close the
  106.  *     text file in the current "text area" and return NIL.
  107.  *  $DESCRIPTION$
  108.  *     The FT_F*() file functions are for reading text files, that is,
  109.  *     files where each line (record) is delimited by a CRLF pair.
  110.  *
  111.  *     Each file is opened in its own "workarea", similar to the concept
  112.  *     use by dbf files.  As provided, a maximum of 10 files (in 10
  113.  *     workareas) can be opened (assuming there are sufficient file
  114.  *     handles available).  That number may be increased by modifying
  115.  *     the #define TEXT_WORKAREAS in the C source code and recompiling.
  116.  *  $EXAMPLES$
  117.  *     FT_FUSE( "text.c" )      // open text file
  118.  *     DO WHILE !FT_FEOF()
  119.  *        ? FT_FREADLN()
  120.  *        FT_FSKIP()
  121.  *     ENDDO
  122.  *     FT_FUSE()                // close file
  123.  *  $SEEALSO$
  124.  *     FT_FUSE() FT_FSELECT()
  125.  *  $END$
  126.  */
  127.  
  128. void pascal ft_fuse()
  129. {
  130.  
  131.    if ( ISCHAR(1) ) {
  132.       handles[area] = _topen( _parc(1), O_RDONLY|SH_DENYNO|O_BINARY );
  133.       offset[area] = 0;
  134.       recno[area] = 1;
  135.       b = _exmgrab( b_size );
  136.       c = _exmgrab( c_size );
  137.       lastbyte[area] = _tlseek( handles[area], 0L, SEEK_END );
  138.       _retni( handles[area] );
  139.    }
  140.    else {
  141.       _tclose( handles[area] );
  142.       _exmback( b, b_size );
  143.       _exmback( c, c_size );
  144.       _retni(1);
  145.       recno[area] = 0L;
  146.       offset[area] = 0L;
  147.       handles[area] = 0;
  148.       last_rec[area] = 0L;
  149.       last_off[area] = 0L;
  150.       lastbyte[area] = 0L;
  151.       isEof[area] = 0;
  152.    }
  153. }
  154.  
  155.  
  156. /*  $DOC$
  157.  *  $FUNCNAME$
  158.  *     FT_FSELECT()
  159.  *  $CATEGORY$
  160.  *     File I/O
  161.  *  $ONELINER$
  162.  *     Select a text file workarea
  163.  *  $SYNTAX$
  164.  *     FT_FSELECT( <nArea> ) -> nArea
  165.  *  $ARGUMENTS$
  166.  *     <nArea> is the text file workarea to select.
  167.  *  $RETURNS$
  168.  *     The current selected text file area if no parameter is passed,
  169.  *     otherwise the previous area if a new area is selected.
  170.  *  $DESCRIPTION$
  171.  *     This function selects a text file "workarea" from 1 to 10.  A
  172.  *     file may or may not be open in the selected area.
  173.  *
  174.  *     Each file is opened in its own "workarea", similar to the concept
  175.  *     used by dbf files.  As provided, a maximum of 10 files (in 10
  176.  *     workareas) can be opened (assuming there are sufficient file
  177.  *     handles available).  That number may be increased by modifying
  178.  *     the #define TEXT_WORKAREAS in the C source code and recompiling.
  179.  *
  180.  *     All the FT_F*() file functions operate on the file in the currently
  181.  *     selected text file workarea.
  182.  *
  183.  *     Text file workareas are separate from and independent of Clipper's
  184.  *     database workareas.
  185.  *  $EXAMPLES$
  186.  *     FT_FSELECT(1)
  187.  *     nFile1 := FT_FUSE( "temp.c" )
  188.  *     ? FT_FLASTREC()                 // no. of lines in temp.c
  189.  *     FT_FSELECT(2)
  190.  *     nFile2 := FT_FUSE( "temp.h" )
  191.  *     ? FT_FLASTREC()                 // no. of lines in temp.h
  192.  *  $SEEALSO$
  193.  *     FT_FUSE()
  194.  *  $END$
  195.  */
  196.  
  197. void pascal ft_fselect()
  198. {
  199.  
  200.    _retni( area + 1 );
  201.  
  202.    if ( ISNUM(1) )
  203.       area = _parni(1) - 1;
  204.  
  205. }
  206.  
  207. /*  $DOC$
  208.  *  $FUNCNAME$
  209.  *     FT_FGOTOP()
  210.  *  $CATEGORY$
  211.  *     File I/O
  212.  *  $ONELINER$
  213.  *     Go to the first record in a text file
  214.  *  $SYNTAX$
  215.  *     FT_FGOTOP() -> NIL
  216.  *  $ARGUMENTS$
  217.  *     None
  218.  *  $RETURNS$
  219.  *     NIL
  220.  *  $DESCRIPTION$
  221.  *     This function moves the record pointer to the first record
  222.  *     in the currently selected text file workarea.
  223.  *
  224.  *     A text file "record" is a line of text terminated by a CRLF pair.
  225.  *  $EXAMPLES$
  226.  *     FT_FUSE( "text.c" )      // open text file
  227.  *     DO WHILE !FT_FEOF()
  228.  *        ? FT_FREADLN()        // read thru file
  229.  *        FT_FSKIP()
  230.  *     ENDDO
  231.  *     FT_FGOTOP()              // go back to top
  232.  *     ? FT_FRECNO()            // 1
  233.  *  $SEEALSO$
  234.  *     FT_FSELECT() FT_FUSE() FT_FRECNO() FT_FGOBOT()
  235.  *  $END$
  236.  */
  237.  
  238. void pascal ft_fgotop()
  239. {
  240.  
  241.    offset[area] = 0L;
  242.    recno[area] = 1L;
  243.  
  244. }
  245.  
  246.  
  247. /*  $DOC$
  248.  *  $FUNCNAME$
  249.  *     FT_FRECNO()
  250.  *  $CATEGORY$
  251.  *     File I/O
  252.  *  $ONELINER$
  253.  *     Return the current record number of a text file
  254.  *  $SYNTAX$
  255.  *     FT_FRECNO() -> nRecNo
  256.  *  $ARGUMENTS$
  257.  *     None
  258.  *  $RETURNS$
  259.  *     The current record number of a text file or 0 if no file is open.
  260.  *  $DESCRIPTION$
  261.  *     This function returns the current record number of the file open
  262.  *     in the currently selected text file workarea.
  263.  *
  264.  *     A text file "record" is a line of text terminated by a CRLF pair.
  265.  *  $EXAMPLES$
  266.  *     FT_FUSE( "text.c" )      // open text file
  267.  *     DO WHILE !FT_FEOF()
  268.  *        ? FT_FREADLN()        // read thru file
  269.  *        FT_FSKIP()
  270.  *     ENDDO
  271.  *     FT_FGOTOP()              // go back to top
  272.  *     ? FT_FRECNO()            // 1
  273.  *  $SEEALSO$
  274.  *      FT_FSELECT() FT_FUSE() FT_FGOTOP() FT_FGOBOT()
  275.  *  $END$
  276.  */
  277.  
  278.  
  279. void pascal ft_frecno()
  280. {
  281.  
  282.    _retnl( recno[area] );
  283.  
  284. }
  285.  
  286.  
  287. /*  $DOC$
  288.  *  $FUNCNAME$
  289.  *     FT_FGOBOT()
  290.  *  $CATEGORY$
  291.  *     File I/O
  292.  *  $ONELINER$
  293.  *     Go to the last record in a text file
  294.  *  $SYNTAX$
  295.  *     FT_FGOBOT() -> NIL
  296.  *  $ARGUMENTS$
  297.  *     None
  298.  *  $RETURNS$
  299.  *     NIL
  300.  *  $DESCRIPTION$
  301.  *     This function moves the record pointer to the last record of the
  302.  *     file in the currently selected text file workarea.
  303.  *
  304.  *     A text file "record" is a line of text terminated by a CRLF pair.
  305.  *  $EXAMPLES$
  306.  *     // read last line
  307.  *     FT_FUSE( "text.c" )
  308.  *     FT_FGOBOT()
  309.  *     ? FT_FREADLN()
  310.  *  $SEEALSO$
  311.  *     FT_FSELECT() FT_FUSE() FT_FGOTOP() FT_FRECNO() FT_FREADLN()
  312.  *  $END$
  313.  */
  314.  
  315.  
  316. void pascal ft_fgobot()
  317. {
  318.  
  319.    int x;
  320.    int len;
  321.    long loc;
  322.  
  323.    if ( last_rec[area] != 0 ) {
  324.       recno[area] = last_rec[area];
  325.       offset[area] = last_off[area];
  326.    }
  327.    else {
  328.  
  329.       loc = 0L;
  330.  
  331.       do {
  332.  
  333.          _tlseek( handles[area], offset[area], SEEK_SET );
  334.          len = _tread(  handles[area], c, c_size );
  335.          for ( x = 0; x < len; x++ ) {
  336.             if ( ((*(c + x) == 13) && (*(c + x + 1) == 10)) ||
  337.                  ((*(c + x) == 10) && (*(c + x + 1) == 13)) ||
  338.                  ( x - loc > b_size ) ) {
  339.                recno[area]++;
  340.                x++;
  341.                loc = x + 1;
  342.             }
  343.          }
  344.          offset[area] += loc;
  345.  
  346.       } while ( len == c_size );
  347.  
  348.       last_rec[area] = --recno[area];
  349.       last_off[area] = offset[area];
  350.  
  351.    }
  352. }
  353.  
  354.  
  355. /*  $DOC$
  356.  *  $FUNCNAME$
  357.  *     FT_FSKIP()
  358.  *  $CATEGORY$
  359.  *     File I/O
  360.  *  $ONELINER$
  361.  *     Move the record pointer to a new position in a text file
  362.  *  $SYNTAX$
  363.  *     FT_FSKIP( [ <nLines> ] ) -> NIL
  364.  *  $ARGUMENTS$
  365.  *     <nLines> is the number of lines to skip.  Defaults to 1 if
  366.  *     not specified.
  367.  *  $RETURNS$
  368.  *     NIL
  369.  *  $DESCRIPTION$
  370.  *     This function moves the text file record pointer, similar to
  371.  *     the CLIPPER SKIP command.
  372.  *
  373.  *     A text file "record" is a line of text terminated by a CRLF pair.
  374.  *  $EXAMPLES$
  375.  *     // display each record of a text file
  376.  *     FT_FUSE( "text.c" )
  377.  *     DO WHILE ! FT_FEOF()
  378.  *        ? FT_FREADLN()
  379.  *        FT_FSKIP()
  380.  *     ENDDO
  381.  *  $SEEALSO$
  382.  *     FT_FRECNO() FT_FGOTOP() FT_FGOBOT()
  383.  *  $END$
  384.  */
  385.  
  386. void pascal ft_fskip()
  387. {
  388.  
  389.    if ( ISNUM(1) )
  390.       _ft_skip( _parni(1) );
  391.    else
  392.       _ft_skip(1);
  393.  
  394. }
  395.  
  396.  
  397. static long _ft_skip( int recs )
  398. {
  399.  
  400.    int x;
  401.    long read_pos;
  402.    size_t read_len;
  403.    long y;
  404.  
  405.  
  406.    if ( recs > 0 ) {
  407.       for (y = 0; y < recs; y++ ) {
  408.          _tlseek( handles[area], offset[area], SEEK_SET );
  409.          read_len = _tread( handles[area], b, b_size );
  410.          for (x = 0; x < read_len; x++ ) {
  411.             if ( ((*(b + x) == 13) && (*(b + x + 1) == 10)) ||
  412.                  ((*(b + x) == 10) && (*(b + x + 1) == 13)) ) {
  413.                break;
  414.             }
  415.          }
  416.          if ( (offset[area] + x + 2) < lastbyte[area] ) {
  417.             isEof[area] = FALSE;
  418.             offset[area] += (x + 2);
  419.             recno[area] += 1;
  420.          }
  421.          else
  422.             isEof[area] = TRUE;
  423.       }
  424.    }
  425.    else {
  426.       recs = -recs;
  427.       isEof[area] = FALSE;
  428.  
  429.       if ( (recno[area] - recs) < 1 )
  430.          return( 1 );
  431.  
  432.       for (y = recs; y > 0; y-- ) {
  433.          if ( offset[area] - b_size < 0L ) {
  434.             read_pos = 0;
  435.             read_len = (size_t)offset[area];
  436.          }
  437.          else {
  438.             read_pos = (size_t)(offset[area] - b_size);
  439.             read_len = b_size;
  440.          }
  441.  
  442.          _tlseek( handles[area], read_pos, SEEK_SET );
  443.          read_len = _tread( handles[area], b, read_len );
  444.  
  445.          for (x = read_len - 4; x >= 0; x-- ) {
  446.             if ( ((*(b + x) == 13) && (*(b + x + 1) == 10)) ||
  447.                  ((*(b + x) == 10) && (*(b + x + 1) == 13)) ) {
  448.                break;
  449.             }
  450.          }
  451.          if ( x < 0 ) {
  452.             offset[area] = 0;
  453.             recno[area] = 1;
  454.          }
  455.          else {
  456.             offset[area] = read_pos + x + 2;
  457.             recno[area]--;
  458.          }
  459.       }
  460.    }
  461.  
  462.    return ( recno[area] );
  463. }
  464.  
  465.  
  466. /*  $DOC$
  467.  *  $FUNCNAME$
  468.  *     FT_FREADLN()
  469.  *  $CATEGORY$
  470.  *     File I/O
  471.  *  $ONELINER$
  472.  *     Read a line from the currently selected text file
  473.  *  $SYNTAX$
  474.  *     FT_FREADLIN() -> cLine
  475.  *  $ARGUMENTS$
  476.  *     None
  477.  *  $RETURNS$
  478.  *     A string containing the current record in a text file.
  479.  *  $DESCRIPTION$
  480.  *     This function returns a line of text read from the file in the
  481.  *     currently selected text file workarea.  Text lines are delimited
  482.  *     with a CRLF pair.  The record pointer is not moved.
  483.  *
  484.  *     A text file "record" is a line of text terminated by a CRLF pair.
  485.  *  $EXAMPLES$
  486.  *     // display each record of a text file
  487.  *     FT_FUSE( "text.c" )
  488.  *     DO WHILE ! FT_FEOF()
  489.  *        ? FT_FREADLN()
  490.  *        FT_FSKIP()
  491.  *     ENDDO
  492.  *  $SEEALSO$
  493.  *     FT_FUSE() FT_FRECNO() FT_FGOTOP() FT_FGOBOT()
  494.  *  $END$
  495.  */
  496.  
  497.  
  498. void pascal ft_freadln()
  499. {
  500.  
  501.    int x;
  502.    long read;
  503.  
  504.    _tlseek( handles[area], offset[area], SEEK_SET );
  505.    read = _tread( handles[area], b, b_size );
  506.  
  507.    for ( x = 0; x < b_size; x++ ) {
  508.       if ( ((*(b + x) == 13) && (*(b + x + 1) == 10)) ||
  509.            ((*(b + x) == 10) && (*(b + x + 1) == 13)) ||
  510.            (*(b + x) == 26) || ( x >= (int)read) ) {
  511.          break;
  512.       }
  513.    }
  514.    _retclen( b, x );
  515.  
  516. }
  517.  
  518.  
  519. /*  $DOC$
  520.  *  $FUNCNAME$
  521.  *     FT_FLASTREC()
  522.  *  $CATEGORY$
  523.  *     File I/O
  524.  *  $ONELINER$
  525.  *     Determine the no. of records in the currently selected text file
  526.  *  $SYNTAX$
  527.  *     FT_FLASTREC() -> nLastRecordNum
  528.  *  $ARGUMENTS$
  529.  *     None
  530.  *  $RETURNS$
  531.  *     An integer containing the number of records in the text file in
  532.  *     the currently selected text file workarea, or zero if no file
  533.  *     is currently open in the workarea.
  534.  *  $DESCRIPTION$
  535.  *     This function returns the number of the last record in a text file.
  536.  *
  537.  *     A text file "record" is a line of text terminated by a CRLF pair.
  538.  *  $EXAMPLES$
  539.  *     FT_FUSE( "text.c" )
  540.  *     ? FT_FLASTREC()
  541.  *  $SEEALSO$
  542.  *     FT_FUSE() FT_FGOBOT() FT_FRECNO()
  543.  *  $END$
  544.  */
  545.  
  546.  
  547. void pascal ft_flastre()
  548. {
  549.  
  550.    long old_rec;
  551.    long old_offset;
  552.  
  553.    old_rec = recno[area];
  554.    old_offset = offset[area];
  555.  
  556.    ft_fgobot();
  557.    _retnl( last_rec[area] );
  558.  
  559.    recno[area] = old_rec;
  560.    offset[area] = old_offset;
  561.  
  562. }
  563.  
  564.  
  565. /*  $DOC$
  566.  *  $FUNCNAME$
  567.  *     FT_FEOF()
  568.  *  $CATEGORY$
  569.  *     File I/O
  570.  *  $ONELINER$
  571.  *     Determine when end of text file is encountered
  572.  *  $SYNTAX$
  573.  *     FT_FEOF() -> lResult
  574.  *  $ARGUMENTS$
  575.  *     None
  576.  *  $RETURNS$
  577.  *     .T. if an attempt was made to skip past the last record of
  578.  *     the currently selected text file, otherwise .F.
  579.  *  $DESCRIPTION$
  580.  *     This function is similar to the CLIPPER Eof() function.
  581.  *
  582.  *     A text file "record" is a line of text terminated by a CRLF pair.
  583.  *  $EXAMPLES$
  584.  *     FT_FUSE( "FTTEXT.C" )
  585.  *     FT_FGOBOT()
  586.  *     ? FT_FEOF()        // .F.
  587.  *     FT_FSKIP()
  588.  *     ? FT_FEOF()        // .T.
  589.  *  $SEEALSO$
  590.  *     FT_FUSE() FT_FGOBOT() FT_FSKIP()
  591.  *  $END$
  592.  */
  593.  
  594.  
  595. void pascal ft_feof()
  596. {
  597.    _retl( isEof[area] );
  598. }
  599.  
  600.  
  601. /*  $DOC$
  602.  *  $FUNCNAME$
  603.  *     FT_FGOTO()
  604.  *  $CATEGORY$
  605.  *     File I/O
  606.  *  $ONELINER$
  607.  *     Move record pointer to specific record in a text file
  608.  *  $SYNTAX$
  609.  *     FT_FGOTO( nLine ) -> NIL
  610.  *  $ARGUMENTS$
  611.  *     <nLine> is the record number to go to.
  612.  *  $RETURNS$
  613.  *     NIL
  614.  *  $DESCRIPTION$
  615.  *     This function moves the record pointer to a specific record
  616.  *     in the file in the currently selected text file workarea.  If
  617.  *     the record number requested is greater than the number of records
  618.  *     in the file, the record pointer will be positioned at the last
  619.  *     record.
  620.  *
  621.  *     A text file "record" is a line of text terminated by a CRLF pair.
  622.  *  $EXAMPLES$
  623.  *     // read 5th line of text from file
  624.  *     FT_FUSE( "FTTEXT.C" )
  625.  *     FT_FGOTO(5)
  626.  *     cText := FT_FREADLN()
  627.  *  $SEEALSO$
  628.  *    FT_FRECNO() FT_FGOTOP() FT_FGOBOT() FT_FREADLN()
  629.  *  $END$
  630.  */
  631.  
  632. void pascal ft_fgoto()
  633. {
  634.  
  635.    long target;
  636.    long last;
  637.  
  638.    target = _parnl(1);
  639.    last = 0;
  640.  
  641.    if ( recno[area] > target ) {
  642.       while ( recno[area] != target )   {
  643.          last = recno[area];
  644.          _ft_skip(-1);
  645.          if ( recno[area] == last )
  646.             break;
  647.       }
  648.    }
  649.    else {
  650.       while ( recno[area] != target ) {
  651.          last = recno[area];
  652.          _ft_skip(1);
  653.          if ( recno[area] == last )
  654.             break;
  655.       }
  656.    }
  657. }
  658.  
  659.  
  660.